import org.geotools.data.*;
import org.geotools.data.simple.*;
import org.geotools.factory.*;
import org.geotools.geojson.*;
import org.geotools.geojson.geom.*;
import org.locationtech.jts.geom.*;
import org.opengis.feature.simple.*;
import org.opengis.filter.*;
import org.opengis.filter.identity.*;

/**
 * 矢量数据操作类
 * 目前只有‘属性的查询and编辑’
 */
public class VectorOperation {
    DataStore mcPGDataStore=null;

    private void initDataStore()throws Exception{
        //获取DataStore对象
        //综合考虑时，还需要区分是连接的数据库还是普通shp数据
        //后期可以改造这里，从而连接不同的数据源种类
        mcPGDataStore=connPostGIS.connPg();
    }

    /**
     * 根据属性值查找矢量要素
     * @param pFeatureClass 要素类名称
     * @param pFieldName 属性列名称
     * @param pFieldValue 属性值
     * @throws Exception
     */
    public void queryVectorbyAttrs(String pFeatureClass, String pFieldName, String pFieldValue)throws Exception {
        //获取数据源
        initDataStore();
        //打开要素类
        SimpleFeatureSource sfsSource = mcPGDataStore.getFeatureSource(pFeatureClass);
        //创建查询器(不区分大小写)
        FilterFactory factoryFilter = CommonFactoryFinder.getFilterFactory();
        Filter filterName = factoryFilter.equal(factoryFilter.property(pFieldName),
                factoryFilter.literal(pFieldValue), false);
        
        SimpleFeatureCollection feaFiltered = sfsSource.getFeatures(filterName);
        //下面这种方式也可以输出查询结果
        SimpleFeatureIterator feaIterator = feaFiltered.features();
        while (feaIterator.hasNext()) {
            SimpleFeature tFeaCurrent = feaIterator.next();
            System.out.println("=====属性查询结果=====");
            System.out.println("城市名称：" + tFeaCurrent.getAttribute("CITY_NAME"));
            System.out.println("所属国家：" + tFeaCurrent.getAttribute("CNTRY_NAME"));
        }
        //释放对象
        feaIterator.close();
        mcPGDataStore.dispose();
    }

    /**
     * 矢量要素属性编辑
     * @param pFeatureClass 要素类名称
     * @param pFIDValue 要素fid值（类似于以前的EventID）
     * @param pFieldName 字段名称
     * @param pFieldValue 待修改的字段值
     * @throws Exception
     */
    public void editVectorAttrs(String pFeatureClass, int pFIDValue, String pFieldName, Object pFieldValue)throws Exception{
        //查询过程，首先需要获取待修改的要素，也就是需要一个查询条件；
        //其次，需要修改的内容：即修改哪个字段，修改成什么值
        //获取数据源
        initDataStore();
        //打开要素类
        SimpleFeatureSource sfsSource=mcPGDataStore.getFeatureSource(pFeatureClass);
        //创建查询器(不区分大小写)
//        FilterFactory factoryFilter= CommonFactoryFinder.getFilterFactory();
//        //没有fid字段？
//        Filter filterName=factoryFilter.equal(factoryFilter.property("fid"),
//                factoryFilter.literal(pFIDValue),false);
        FilterFactory2 factory2=CommonFactoryFinder.getFilterFactory2();
        FeatureId feaid= factory2.featureId(String.valueOf(pFIDValue));
        Filter fidFilter=factory2.id(feaid);
        Transaction editTransaction=new DefaultTransaction("update");
        SimpleFeatureStore editFeatureStore=(SimpleFeatureStore)sfsSource;
        editFeatureStore.setTransaction(editTransaction);
        try {
            editFeatureStore.modifyFeatures(pFieldName,pFieldValue,fidFilter);
            editTransaction.commit();
            System.out.println("Edit Success!");
        }catch (Exception error){
            System.out.println("Edit Field.");
            error.printStackTrace();
            editTransaction.rollback();
        }finally {
            editTransaction.close();
        }
    }
    
    /**
     * 目前所搜索到的空间查询方式：
     * （1）使用CQL，这种方式过时了么？其语法是什么样呢？
     * （2）使用filter循环查询，判断一个shp中的所有几何是否与当前给定的polygon相交并输出结果
     */
    /**
     * 根据空间轮廓查询矢量要素
     * @param pFeatureClass 执行查询的要素类名称
     * @param geoQuery 用于查询的空间轮廓（矩形/圆形）
     * @throws Exception
     */
    public void queryVectorbySpatial(String pFeatureClass, Geometry geoQuery) throws Exception {
        //获取数据源
        initDataStore();
        //打开要素类
        SimpleFeatureSource sfsSource = mcPGDataStore.getFeatureSource(pFeatureClass);
        SimpleFeatureCollection feaCollection = sfsSource.getFeatures();
        SimpleFeatureIterator feaIT = feaCollection.features();
        int count = 0;
        while (feaIT.hasNext()) {
            SimpleFeature feaCurrent = feaIT.next();
            Geometry geoCurrent = (Geometry) feaCurrent.getDefaultGeometry();
            if (geoQuery.intersects(geoCurrent)) {
                System.out.println("选中了:" + feaCurrent.getAttribute("cntry_name"));
                count++;
            }
        }
        System.out.println("一共选中了 [" + count + "] 个要素");
        //能否用查询器方式直接进行查询，而不是使用循环呢？
        //创建查询器(不区分大小写)
//		FilterFactory2 filterFacotry = CommonFactoryFinder.getFilterFactory2();
//        CQL.toCQL("")
        //无法把两个Geometry互相转换，这里报错
//		Intersects spatialFilter = filterFacotry.intersects("the_geom", geoQuery);
    }
    public void queryVectorbySpatial(String pFeatureClass, String geoQueryGeoJsonStr) throws Exception {
//        MathTransform transform = CRS.findMathTransform(DefaultGeographicCRS.WGS84,);
        GeometryJSON gjson = new GeometryJSON();
        //这里得到的polygon依旧是JTS的几何类型
        Polygon geometryQuery = gjson.readPolygon(GeoJSONUtil.toReader(geoQueryGeoJsonStr));
        //获取数据源
        initDataStore();
        //打开要素类
        SimpleFeatureSource sfsSource = mcPGDataStore.getFeatureSource(pFeatureClass);
        SimpleFeatureCollection feaCollection = sfsSource.getFeatures();
        SimpleFeatureIterator feaIT = feaCollection.features();
        int count = 0;
        while (feaIT.hasNext()) {
            SimpleFeature feaCurrent = feaIT.next();
            Geometry geoCurrent = (Geometry) feaCurrent.getDefaultGeometry();
            if (geometryQuery.intersects(geoCurrent)) {
                System.out.println("选中了:" + feaCurrent.getAttribute("cntry_name"));
                count++;
            }
        }
        System.out.println("一共选中了 [" + count + "] 个要素");
    }
    
    public void editVectorGeometry(String pFeatureClass,int pFid, String pGeoStrNew)throws Exception{
        //根据String构造新的几何(按照从屏幕获取GeoJson字符串的方式来写)
        GeometryJSON gjson = new GeometryJSON();
        Geometry geometryNew= gjson.read(GeoJSONUtil.toReader(pGeoStrNew));
        //更改几何
        editVectorGeometry(pFeatureClass,pFid,geometryNew);
    }
    public void editVectorGeometry(String pFeatureClass,int pFid, Geometry pGeoNew)throws Exception {
        /* 思路：
        首先获取需要修改的要素；
        将新传入的几何赋给该要素；
        最后保存并关闭连接。
        注：下面这种方式是可以成功更改几何的，
        因此现在的问题就变成了‘修改几何’是什么样的方式呢？直接编辑点(线or面的某些节点)的位置？
        那么这样可以获取屏幕上新的几何的所有坐标顺序，然后就可以直接更改要素的几何值了
         */
        //(1)获取待修改的要素
        SimpleFeature feaEditing = null;
        initDataStore();//初始化数据源（PostGIS数据）
        SimpleFeatureSource sfsSource = mcPGDataStore.getFeatureSource(pFeatureClass);//打开要素类
        FilterFactory2 factory2 = CommonFactoryFinder.getFilterFactory2();
        FeatureId feaid = factory2.featureId(String.valueOf(pFid));
        Filter fidFilter = factory2.id(feaid);
        //(2)开启编辑事务
        Transaction editTransaction = new DefaultTransaction("update");
        SimpleFeatureStore editFeatureStore = (SimpleFeatureStore) sfsSource;
        editFeatureStore.setTransaction(editTransaction);
        //(3)修改要素几何
        try {
            editFeatureStore.modifyFeatures("the_geom", pGeoNew, fidFilter);
            editTransaction.commit();
            System.out.println("Edit Success!");
        } catch (Exception error) {
            System.out.println("Edit Field.");
            error.printStackTrace();
            editTransaction.rollback();
        } finally {
            editTransaction.close();
        }
    }
}
